<template>
  <div class="table-container">
    <el-card style="margin-top: 20px">
      <slot name="top"></slot>
      <el-table
        style="width: 100%"
        ref="table"
        :border="border"
        :row-key="rowKey"
        :size="tableSize"
        :tree-props="treeProps"
        :data="asyncData"
        v-loading="loading"
        highlight-current-row
        @selection-change="(e) => $emit('selection-change', e)"
        @cell-dblclick="handleCellDblclick"
      >
        <template v-for="(item, index) in columns">
          <!-- 插槽 -->
          <el-table-column
            v-if="item.type === 'slot'"
            v-bind="item"
            :key="index"
            :align="item.align || 'center'"
            show-overflow-tooltip
          >
            <template slot-scope="scope">
              <slot :name="item.slotName" v-bind="{ row: scope.row, $index: scope.$index }"></slot>
            </template>
          </el-table-column>
          <!-- 索引 -->
          <el-table-column
            v-else-if="item.type === 'index'"
            v-bind="item"
            :key="index"
            :align="item.align || 'center'"
            show-overflow-tooltip
          >
            <template scope="scope">
              <span>{{ (page - 1) * size + scope.$index + 1 }}</span>
            </template>
          </el-table-column>
          <!-- 其他 -->
          <el-table-column
            v-else
            v-bind="item"
            :key="index"
            :align="item.align || 'center'"
            show-overflow-tooltip
          ></el-table-column>
        </template>
      </el-table>
      <el-pagination
        v-show="showPagination"
        :page-sizes="pagination.pageSizes"
        :layout="pagination.layout"
        :current-page="page"
        :page-size="size"
        :total="total"
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
      >
      </el-pagination>
    </el-card>
  </div>
</template>

<script>
export default {
  name: 'XlTable',
  props: {
    // 是否边框
    border: {
      type: Boolean,
      default: true
    },
    // 表格大小
    tableSize: {
      type: String,
      default: 'medium'
    },
    // 显示分页
    showPagination: {
      type: Boolean,
      default: true
    },
    // 展示树结构时指定的key
    rowKey: {
      type: String,
      default: ''
    },
    // 渲染树结构的配置选项
    treeProps: {
      type: Object,
      default: () => {}
    },
    // 表格展示的字段
    columns: {
      type: Array,
      default: () => []
    },
    // 静态数据
    staticData: {
      type: Array,
      default: () => []
    },
    // 双击编辑
    doubleEdit: {
      type: Boolean,
      default: false
    },
    // 请求函数
    action: {
      type: Function,
      default: null
    },
    // 是否初始化加载数据
    actionInit: {
      type: Boolean,
      default: true
    },
    // 初始化参数
    actionParams: {
      type: Object,
      default: () => {}
    },
    // 页码配置
    pagination: {
      type: Object,
      default: () => {
        return {
          pageSizes: [10, 20, 30, 50, 100],
          layout: 'total, sizes, prev, pager, next, jumper'
        }
      }
    }
  },
  data() {
    return {
      asyncData: [], // 表格数据
      loading: false, // 加载状态
      page: 1, // 页数
      size: 10, // 每页数据
      total: 0, // 总条数
      // cacheParams: {}, // 缓存参数
      isInnerChange: false // 是否内部修改
    }
  },
  created() {
    if (this.staticData.length && this.action) {
      throw new Error('data or action can only have one property !!')
    } else if (this.staticData.length) {
      this.asyncData = this.staticData
    } else if (this.action && this.actionInit) {
      this.loadData()
    }
  },
  methods: {
    async loadData(params) {
      if (this.loading) return
      this.loading = true

      const options = {
        page: this.isInnerChange ? this.page : 1,
        size: this.size,
        ...params,
        ...this.actionParams
      }

      try {
        const res = await this.action(options)
        this.loading = false
        this.isInnerChange = false
        this.asyncData = res.data.list || []
        this.total = res.data.count || 0
      } catch (err) {
        console.log(err)
        this.loading = false
        this.isInnerChange = false
        this.asyncData = []
        this.total = 0
      }
    },
    // 双击单元格触发
    handleCellDblclick(row, column, cell, event) {
      if (!this.doubleEdit) return
      if (column.type === 'expand') return

      const save = function (e) {
        e.clipboardData.setData('text/plain', event.target.innerText)
        e.preventDefault()
      }

      document.addEventListener('copy', save)
      document.execCommand('copy')
      document.removeEventListener('copy', save)
      this.$message({ message: '复制成功', type: 'success' })
    },
    // 修改每页显示条数
    handleSizeChange(val) {
      this.page = 1
      this.size = val
      this.isInnerChange = true
      if (this.action) this.loadData()
    },
    // 修改当前页
    handleCurrentChange(val) {
      this.page = val
      this.isInnerChange = true
      if (this.action) this.loadData()
    }
  }
}
</script>

<style lang="scss" scoped>
.el-pagination {
  margin-top: 15px;
  text-align: right;
}
</style>
